package web

import (
	"context"
	"embed"
	"io/fs"
	"net/http"
	"path"
	"sync"
	"tikrok/internal/client/mvc"
	"tikrok/internal/log"
	"tikrok/internal/proto"
	"tikrok/internal/util"
	"time"

	"github.com/gorilla/websocket"
)

// 修复1：使用标准库嵌入资源
//
//go:embed templates/*
var staticAssets embed.FS

type WebView struct {
	log.Logger

	ctl        mvc.Controller
	wsMessages *util.Broadcast
	server     *http.Server       // 新增：支持优雅关闭
	wsConns    sync.Map           // 新增：跟踪活跃连接
	wsUpgrader websocket.Upgrader // 新增：安全升级配置
}

func NewWebView(ctl mvc.Controller, addr string) *WebView {
	wv := &WebView{
		Logger:     log.NewPrefixLogger("view", "web"),
		wsMessages: util.NewBroadcast(),
		ctl:        ctl,
		wsUpgrader: websocket.Upgrader{
			ReadBufferSize:  1024,
			WriteBufferSize: 1024,
			// 修复2：增加来源检查
			CheckOrigin: func(r *http.Request) bool {
				return r.Header.Get("Origin") == "http://"+r.Host
			},
		},
	}

	mux := http.NewServeMux()

	// 保持原有路由逻辑
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, "/http/in", http.StatusFound)
	})

	mux.HandleFunc("/_ws", wv.wsHandler)
	mux.HandleFunc("/static/", wv.staticHandler)

	// 修复3：配置安全超时
	wv.server = &http.Server{
		Addr:         addr,
		Handler:      mux,
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 10 * time.Second,
		IdleTimeout:  60 * time.Second,
	}

	wv.Info("Serving web interface on %s", addr)
	wv.ctl.Go(func() {
		// 修复4：处理监听错误
		if err := wv.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			wv.Error("HTTP server error: %v", err)
		}
	})
	return wv
}

// 修复5：完善WebSocket处理
func (wv *WebView) wsHandler(w http.ResponseWriter, r *http.Request) {
	conn, err := wv.wsUpgrader.Upgrade(w, r, nil)
	if err != nil {
		wv.Warn("WebSocket upgrade failed: %v", err)
		return
	}
	defer conn.Close()

	// 跟踪连接
	wv.wsConns.Store(conn, struct{}{})
	defer wv.wsConns.Delete(conn)

	msgs := wv.wsMessages.Reg()
	defer wv.wsMessages.UnReg(msgs)

	for {
		select {
		case m := <-msgs:
			if err := conn.WriteMessage(websocket.TextMessage, m.([]byte)); err != nil {
				return
			}
		case <-r.Context().Done():
			return
		}
	}
}

// 修复6：安全处理静态资源
func (wv *WebView) staticHandler(w http.ResponseWriter, r *http.Request) {
	// 清理路径防止目录遍历
	cleanPath := path.Clean(r.URL.Path[len("/static/"):])
	fullPath := path.Join("static", cleanPath)

	// 从嵌入文件系统读取
	data, err := fs.ReadFile(staticAssets, fullPath)
	if err != nil {
		if _, ok := err.(*fs.PathError); ok {
			http.NotFound(w, r)
		} else {
			wv.Warn("Static file error: %s - %v", fullPath, err)
			http.Error(w, "Internal server error", http.StatusInternalServerError)
		}
		return
	}

	// 设置缓存头
	w.Header().Set("Cache-Control", "public, max-age=3600")
	//w.Header().Set("Content-Type", detectContentType(fullPath))
	w.Write(data)
}

// 新增：内容类型检测
//func detectContentType(path string) string {
//	switch path.Ext(path) {
//	case ".css":
//		return "text/css"
//	case ".js":
//		return "text/javascript"
//	case ".png":
//		return "image/png"
//	case ".svg":
//		return "image/svg+xml"
//	default:
//		return "text/plain"
//	}
//}

// 修复7：实现优雅关闭
func (wv *WebView) Shutdown() {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	// 关闭所有WebSocket连接
	wv.wsConns.Range(func(key, _ interface{}) bool {
		conn := key.(*websocket.Conn)
		conn.WriteControl(
			websocket.CloseMessage,
			websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""),
			time.Now().Add(time.Second),
		)
		conn.Close()
		return true
	})

	if err := wv.server.Shutdown(ctx); err != nil {
		wv.Error("Server shutdown error: %v", err)
	}
}

// 保持原有方法签名不变
func (wv *WebView) NewHttpView(proto *proto.Http) *WebHttpView {
	return newWebHttpView(wv.ctl, wv, proto)
}
